#!/usr/bin/env python
# -*- coding: UTF-8 -*-
"""
@Project ：turbo
@File    ：models.py
@Author  ：赵加响
@Date    ：2023/4/6 10:17
@Desc    ：
"""
from django.db import models
from django.utils.translation import gettext_lazy as _

from apps.accounts.models import User


class Operate(models.Model):
    code = models.CharField(max_length=32, verbose_name='操作代码')
    name = models.CharField(max_length=32, verbose_name='操作名称')
    name_en = models.CharField(max_length=32, verbose_name='操作英文名称', blank=True, null=True)

    class Meta:
        db_table = 'operates'
        verbose_name = "操作表"
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.name


class Menu(models.Model):
    """
    前端菜单主表
    """
    parent = models.ForeignKey('self', verbose_name="父菜单", blank=True, null=True, on_delete=models.DO_NOTHING)
    code = models.CharField(max_length=20, verbose_name="菜单代码(自定义有规则代码)", unique=True)
    name = models.CharField(max_length=32, verbose_name="前端路由名称", unique=True)
    name_en = models.CharField(max_length=32, verbose_name="前端路由英文名称", unique=True, blank=True, null=True)
    content = models.CharField(max_length=200, verbose_name="权限内容说明")
    sort_rule = models.CharField(max_length=10, verbose_name='排序规则', blank=True, null=True)
    is_active = models.BooleanField(verbose_name="是否有效", default=True)
    is_green_light = models.BooleanField(verbose_name="是否允许所有人访问", default=False)
    operate = models.ManyToManyField(Operate, verbose_name='拥有的菜单权限', blank=True, through='MenuOperate')

    class Meta:
        db_table = 'menus'
        verbose_name = '前端菜单主表'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.name + ' - ' + self.code

    def get_descendants(self):
        """
        递归获取所有子菜单
        """
        return Menu.objects.filter(parent=self)

    def get_ancestors(self):
        """
        获取所有祖先菜单
        """
        ancestors = []
        current = self
        while current.parent_id:
            ancestors.append(current.parent)
            current = current.parent
        return ancestors if len(ancestors) > 0 else current

    def get_full_path(self):
        """
        获取从根菜单到当前菜单的完整路径
        """
        path = []
        menu = self
        while menu:
            path.append(menu)
            menu = menu.parent
        return path[::-1]  # 反转列表，使根菜单在前


class MenuOperate(models.Model):
    menu = models.ForeignKey(Menu, verbose_name="菜单", on_delete=models.CASCADE)
    operate = models.ForeignKey(Operate, verbose_name="操作", on_delete=models.CASCADE)
    is_node = models.BooleanField(verbose_name="是否节点", default=False)

    class Meta:
        db_table = 'menu_operates'
        verbose_name = "菜单操作关系表"
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.menu.name + ' - ' + self.operate.name


class MenuOperateUrls(models.Model):
    REQUEST_METHOD = (
        ('GET', 'GET方法'),
        ('POST', 'POST方法'),
        ('PUT', 'PUT方法'),
        ('DELETE', 'DELETE方法')
    )
    description = models.CharField(max_length=128, verbose_name="描述", unique=True)
    url = models.CharField(max_length=128, verbose_name="URL", blank=True, null=True)
    method = models.CharField(max_length=32, verbose_name="请求方法", choices=REQUEST_METHOD, blank=True, null=True)
    is_active = models.BooleanField(verbose_name="是否有效", default=True, db_index=True)
    menu_operate = models.ForeignKey(MenuOperate, verbose_name="菜单操作", related_name='menu_operate_urls',
                                     on_delete=models.DO_NOTHING)

    class Meta:
        db_table = 'menu_operates_urls'
        verbose_name = "菜单操作URL表"
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.description + ' ' + self.method


class Role(models.Model):
    """
    角色主表
    """
    parent = models.ForeignKey('self', verbose_name="父级角色", blank=True, null=True, on_delete=models.DO_NOTHING)
    code = models.CharField(verbose_name='角色代码', max_length=32, unique=True, db_index=True)
    name_zh = models.CharField(verbose_name='角色中文名称', max_length=128, unique=True)
    name_en = models.CharField(verbose_name='角色英文名称', max_length=128, unique=True)
    content = models.CharField(max_length=200, verbose_name="角色说明", blank=True, null=True)
    is_admin = models.BooleanField(verbose_name='是否是管理员', default=False, db_index=True)
    menu_operate = models.ManyToManyField(MenuOperate, verbose_name='拥有的菜单权限', blank=True,
                                          through='RoleMenuOperate')

    def __str__(self):
        return self.code

    class Meta:
        db_table = "roles"
        verbose_name = "角色"
        verbose_name_plural = verbose_name


class RoleMenuOperate(models.Model):
    role = models.ForeignKey(Role, verbose_name="角色", on_delete=models.CASCADE)
    menu_operate = models.ForeignKey(MenuOperate, verbose_name="菜单操作", on_delete=models.CASCADE)
    is_active = models.BooleanField(verbose_name="是否有效", default=True, db_index=True)

    class Meta:
        db_table = 'role_menu_operates'
        verbose_name = '角色菜单操作设定表'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.role.code + ' (' + self.menu_operate.menu.name + ' + ' + self.menu_operate.operate.name + ')'


class SensitiveFieldType(models.TextChoices):
    """
    敏感字段类型
    """
    DECIMAL = 'D', 'DecimalField'
    CHAR = 'C', 'CharField'


class SensitiveField(models.Model):
    code = models.CharField(max_length=32, verbose_name='敏感字段代码')
    name = models.CharField(max_length=32, verbose_name='敏感字段名称')
    name_en = models.CharField(max_length=32, verbose_name='敏感字段英文名称', blank=True, null=True)
    field_type = models.CharField(max_length=1, verbose_name='敏感字段数据类型', choices=SensitiveFieldType.choices)

    class Meta:
        db_table = 'sensitive_fields'
        verbose_name = "敏感字段表"
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.name + f' ({self.get_field_type_display()})'


class SensitiveFieldPermissionType(models.TextChoices):
    READ = 'R', _('read')
    WRITE = 'W', _('write')
    FORBID = 'N', _('no access')


class MenuSensitiveField(models.Model):
    menu = models.ForeignKey('Menu', verbose_name='菜单', on_delete=models.CASCADE)
    sensitive_field = models.ForeignKey(SensitiveField, verbose_name='敏感字段表', on_delete=models.CASCADE)

    class Meta:
        db_table = 'menu_sensitive_fields'
        verbose_name = "菜单敏感字段表"
        verbose_name_plural = verbose_name
        unique_together = ('menu', 'sensitive_field')

    def __str__(self):
        return f'{self.menu.name} - {self.sensitive_field.name}'


class UserMenuSensitiveField(models.Model):
    user = models.ForeignKey(User, verbose_name='用户', on_delete=models.CASCADE)
    menu_sensitive_field = models.ForeignKey(MenuSensitiveField, verbose_name='菜单敏感字段表',
                                             on_delete=models.CASCADE)
    permission_type = models.CharField(max_length=1, choices=SensitiveFieldPermissionType.choices,
                                       default=SensitiveFieldPermissionType.READ, verbose_name='权限类型')

    class Meta:
        db_table = 'user_menu_sensitive_fields'
        verbose_name = '用户菜单敏感字段表'
        verbose_name_plural = verbose_name

    def __str__(self):
        return f'{self.user.username} - {self.menu_sensitive_field.menu.name} -' \
               f' {self.menu_sensitive_field.sensitive_field.name} - {self.get_permission_type_display()}'

    def has_write_permission(self):
        return self.permission_type == SensitiveFieldPermissionType.WRITE

    def has_read_permission(self):
        return self.permission_type in (SensitiveFieldPermissionType.READ, SensitiveFieldPermissionType.WRITE)

    def has_no_permission(self):
        return self.permission_type == SensitiveFieldPermissionType.FORBID
